﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dx.Common
{
    public class SpecialSymbolsHelper
    {
        /// <summary>
        /// 所有的标点符号(考虑删除)
        /// </summary>
        public readonly static char[] AllPuncts = AllPunctsStr.ToCharArray();
        private const string AllPunctsStr = "\"\'$([{£¥‘“＜〈《【〔〖〝﹙﹛﹝＄（［｛￡￥!%),.:;>?]}¢¨°·ˇˉ―-‐‒–—|｜‖’”…‰′″›℃∶、。〃〉＞》】〕〗〞﹚﹜﹞！＂％＇），．：；？］｀｝～￠~「『」』﹄︶︺︾﹀\\*+＋#/／<≤≥≯±×﹣－∠→²³=ΦφδμεΩσ＃㎝_@«»";//
        /// <summary>
        /// 所有空格。\ue000-\uf899之间都是大空格，迄今为止，只发现了\ue004、\ue006有人使用
        /// 对应的Unicode值分别为：32，160，8194（短空格），12288，57350，61472，9（水平制表符\t，很大的一个空格）,58853。
        /// </summary>
        public readonly static char[] Space = SpaceStr.ToCharArray();
        private const string SpaceStr = "\u0020\u00a0\u2002\u3000\ue004\ue006\uf020\u0009\ue5e5\u0015";
        /// <summary>
        ///段落结束符号。所有换行符等特殊符号的集合：\r\n\f\v\t\a
        /// </summary>
        public readonly static char[] ParaTag = ParaTagStr.ToCharArray();
        private const string ParaTagStr = "\r\n\f\v\t\a";//\v：'\u000B'垂直制表符（跟换行符一个意思，会让下一个字符新行开始输出），\a：'\u0007'响铃符 ，\t：'\u0009'水平制表符，\f：'\u000C'换页符，\r：'\u000D'回车符，\n：'\u000A'换行符

        /// <summary>
        ///段落结束符号。所有换行符等特殊符号的集合（出去换行符\n)：\r\f\v\t\a
        /// </summary>
        public readonly static char[] ParaTagNoN = ParaTagNoNStr.ToCharArray();
        private const string ParaTagNoNStr = "\r\f\v\t\a";//\v：'\u000B'垂直制表符，意思是后面字符换行输出，\a：'\u0007'响铃符 ，\t：'\u0009'水平制表符，\f：'\u000C'换页符，\r：'\u000D'回车符，\n：'\u000A'换行符

        /// <summary>
        /// 分隔句子的，表示一句话结束，真正意义上的整句，包括：逗号、句号。但是不包括顿号、冒号，不包括中英文的点：“.”，因为其容易被作为小数点出现
        /// </summary>
        public readonly static char[] SencEnd = SencEndStr.ToCharArray();
        private const string SencEndStr = "!,;?…。！，；？";

        /// <summary>
        /// 左小括号，人们容易把中英文混写
        /// </summary>
        public readonly static char[] GroupLeftKH = GroupLeftKHStr.ToCharArray();
        private const string GroupLeftKHStr = "(﹙（";
        /// <summary>
        /// 右小括号，人们容易把中英文混写
        /// </summary>
        public readonly static char[] GroupRightKH = GroupRightKHStr.ToCharArray();
        private const string GroupRightKHStr = ")﹚）";

        /// <summary>
        /// 表示编号的字符，比如：0123456789①②③④⑤⑥⑦⑧⑨⑩⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽一二三四
        /// </summary>
        public readonly static char[] NumbsSymbolAll = NumbsSymbolAllStr.ToCharArray();
        private const string NumbsSymbolAllStr = "0123456789０１２３４５６７８９①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇一二三四五六七八九十abcdefghijklmnopqrstABCDEFGHIJKLMNOPQRSTⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩";


        /// <summary>
        /// 汉字数字：零一二三四五六七八九十
        /// </summary>
        public readonly static char[] NumbCn = NumbCnStr.ToCharArray();
        private const string NumbCnStr = "零一二三四五六七八九十";
        /// <summary>
        /// 表示序号的字符，如：.、(﹙（)﹚）第条章节，以及各种冒号
        /// </summary>
        public readonly static char[] SerialTag = (SerialPrevStr + SerialNextStr + NounStartStr).ToCharArray();
        /// <summary>
        /// 序号前缀字符集。如：第(﹙（
        /// </summary>
        public readonly static char[] SerialPrev = SerialPrevStr.ToCharArray();
        private const string SerialPrevStr = "第(﹙（";
        /// <summary>
        /// 序号后缀字符集。如：.、)﹚）条章节，以及各种冒号
        /// </summary>
        public readonly static char[] SerialNext = (SerialNextStr + NounStartStr).ToCharArray();
        private const string SerialNextStr = ".、)﹚）条章节卷部篇步";
        /// <summary>
        /// 一个词语开始前的标记，主要为各种冒号
        /// </summary>
        public readonly static char[] NounStart = NounStartStr.ToCharArray();
        private const string NounStartStr = ":∶：";

        /// <summary>
        /// 所有中文量词
        /// </summary>
        public readonly static char[] Quantifier = QuantifierStr.ToCharArray();
        private const string QuantifierStr = "次回个位条匹头只颗根张片道块粒顿把台件顶枚座栋面扇间堵辆列架艘支场发门轮朵阵场";
        /// <summary>
        /// 分组表示特殊字符（处数字、中文、字母外的符号）。
        /// 第一组：①②③，第二组：⑴⑵⑶，第三组：ⅠⅡⅢ，第四组：ⅰⅱⅲ，第五组：⒈⒉⒊，第六组：㈠㈡㈢
        /// </summary>
        public readonly static char[,] NumbsSymbolGroup = new char[,] {  
            // 中文数字①-⑩  
            { '①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩', '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳' },  
            // 带括号的中文数字⑴-⑽  
            { '⑴', '⑵', '⑶', '⑷', '⑸', '⑹', '⑺', '⑻', '⑼', '⑽', '⑾', '⑿', '⒀', '⒁', '⒂', '⒃', '⒄', '⒅', '⒆', '⒇' },  
            // 大写罗马数字Ⅰ-Ⅹ  
            { 'Ⅰ', 'Ⅱ', 'Ⅲ', 'Ⅳ', 'Ⅴ', 'Ⅵ', 'Ⅶ', 'Ⅷ', 'Ⅸ', 'Ⅹ', 'Ⅺ', 'Ⅻ', 'Ⅼ', 'Ⅽ', 'Ⅾ', 'Ⅿ', 'Ⅿ', 'Ⅿ', 'Ⅿ', 'Ⅿ' },  
            // 小写罗马数字ⅰ-ⅹ  
            { 'ⅰ', 'ⅱ', 'ⅲ', 'ⅳ', 'ⅴ', 'ⅵ', 'ⅶ', 'ⅷ', 'ⅸ', 'ⅹ', 'ⅺ', 'ⅻ', 'ⅼ', 'ⅽ', 'ⅾ', 'ⅿ', 'ↀ', 'ↁ', 'ↂ', 'Ↄ' },  
            // 带圈的阿拉伯数字⒈-⒚, ⒛  
            { '⒈', '⒉', '⒊', '⒋', '⒌', '⒍', '⒎', '⒏', '⒐', '⒑', '⒒', '⒓', '⒔', '⒕', '⒖', '⒗', '⒘', '⒙', '⒚', '⒛' },  
            // 另一种带圈的阿拉伯数字㈠-㈩  
            { '㈠', '㈡', '㈢', '㈣', '㈤', '㈥', '㈦', '㈧', '㈨', '㈩','㈠', '㈡', '㈢', '㈣', '㈤', '㈥', '㈦', '㈧', '㈨', '㈩' },
            // 另一种带圈的阿拉伯数字㈠-㈩  
            { '１', '２', '３', '４', '５', '６', '７', '８', '９', '０','１', '２', '３', '４', '５', '６', '７', '８', '９', '０' }
         };
        /// <summary>
        /// 所有中文量词
        /// </summary>
        public readonly static char[] SpecialSymbol = SpecialSymbolStr.ToCharArray();
        private const string SpecialSymbolStr = "√□■★☑φ●△○";

        /// <summary>
        /// 中文的金额汉字对应的数字。仟则返回1000，万则返回10000
        /// </summary>
        /// <param name="cnChr">壹对应1</param>
        /// <returns>返回对应的数字</returns>
        private static int MoneyCnChrToNumb(char cnChr)
        {
            switch (cnChr)
            {
                case '壹': return 1;
                case '一': return 1;
                case '贰': return 2;
                case '二': return 2;
                case '叁': return 3;
                case '三': return 3;
                case '肆': return 4;
                case '四': return 4;
                case '伍': return 5;
                case '五': return 5;
                case '陆': return 6;
                case '六': return 6;
                case '柒': return 7;
                case '七': return 7;
                case '捌': return 8;
                case '八': return 8;
                case '玖': return 9;
                case '九': return 9;
                case '久': return 9;
                case '拾': return 10;
                case '十': return 10;
                case '佰': return 100;
                case '百': return 100;
                case '仟': return 1000;
                case '千': return 1000;
                case '万': return 10000;
                case '亿': return 100000000;
                default:
                    return 0;
            }

        }

        public static bool IsNumbsSymbolGroup(char chr)
        {
            foreach (var symbol in SpecialSymbolsHelper.NumbsSymbolGroup)
            {
                if (symbol == chr) return true;
            }
            return false;
        }

        /// <summary>
        /// 中文汉字数字（五一类的）转数字。最大支持到:九十九
        /// </summary>
        /// <param name="cnTxt">比如：十一</param>
        /// <returns></returns>
        public static int CnNumbToInt(string cnTxt)
        {
            if (string.IsNullOrEmpty(cnTxt)) return 0;
            int rtnNumb = 0;
            //foreach (char ch in cnTxt)
            for (int i = 0; i < cnTxt.Length; i++)
            {
                char ch = cnTxt[i];
                int numb = MoneyCnChrToNumb(ch);
                if (numb < 10)
                {
                    rtnNumb += numb;
                }
                else
                {
                    if (rtnNumb == 0) { rtnNumb += numb; } else { rtnNumb *= numb; }
                }
            }
            return rtnNumb;
        }

        /// <summary>
        /// 获取类似1.3.2这样的数字变小方式
        /// </summary>
        /// <param name="numbStr">类似：1.2、5.3.6</param>
        /// <returns>整数</returns>
        public static int GetIndexFromNumbStr(string numbStr)
        {
            int rtnVal = 0;
            var arrStr = numbStr.Split('.');
            for (int i = 0; i < arrStr.Length; i++)
            {
                if (int.TryParse(arrStr[i], out int temp))
                {
                    rtnVal += temp * (int)Math.Pow(100, (arrStr.Length - i - 1));
                }
                else
                {
                    rtnVal = 0;
                    break;//出错了，退出
                }
            }
            return rtnVal;
        }

        /// <summary>
        /// 获取符号在组中的位置
        /// </summary>
        /// <param name="chr">符号</param>
        /// <returns>（组序号，在该组的位置），没找打，则返回(-1,-1)</returns>
        public static Tuple<int, int> GetSymbolIndex(char chr)
        {
            var group = NumbsSymbolGroup.GetLength(0);
            var count = NumbsSymbolGroup.GetLength(1);
            for (int i = 0; i < group; i++)
            {
                for (int j = 0; j < count; j++)
                {
                    if (NumbsSymbolGroup[i, j] == chr)
                    {
                        return Tuple.Create(group, count);
                    }
                }
            }
            return Tuple.Create(-1, -1);
        }
    }
}
